package com.hmall.gateway.routers;

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

/**
 * @program: springcloud-study
 * @description:
 * @author: flyduck
 * @create: 2025-04-09 22:23
 **/
@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {

    private final NacosConfigManager nacosConfigManager;
    private final RouteDefinitionWriter routeDefinitionWriter;

    private final String dataId = "gateway-routes.json";
    private final String group = "DEFAULT_GROUP";

    private final Set<String> routeIds = new HashSet<>();



    @PostConstruct
    public void initRouteConfigListener() throws NacosException {
        ConfigService configService = nacosConfigManager.getConfigService();

        //注册监听器并首次拉取配置
        String configInfo = configService.getConfigAndSignListener(dataId, group, 5000, new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }

            @Override
            public void receiveConfigInfo(String configInfo) {
                //监听到配置变更，更新路由表
                updateConfigInfo(configInfo);
            }
        });
        //首次启动时，更新路由表
        updateConfigInfo(configInfo);
    }

    // 更新路由表
    public void updateConfigInfo(String configInfo){
        log.debug("监听到路由配置信息：{}",configInfo);

        //1、解析配置文件转换为RouteDefinition
        List<RouteDefinition> routeDefinitionList = JSONUtil.toList(configInfo, RouteDefinition.class);

        //2、删除旧的路由表
        for (String routeId : routeIds) {
            routeDefinitionWriter.delete(Mono.just(routeId));
        }
        routeIds.clear();

        //3、更新路由表
        for (RouteDefinition routeDefinition : routeDefinitionList) {
            //3.1、更新路由表
            routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
            //3.2、记录路由id，便于下一次更新时删除
            routeIds.add(routeDefinition.getId());
        }
    }
}
